import { message } from 'ant-design-vue'
import { fabric } from 'fabric'

import { DmpImgPaintOptions, PaintResizeOptions, PaintStatus } from '../types/dmp-paint'

enum ERROR_MSG {
  CANVAS_NOT_INIT = '画布未加载',
  IMAGE_NOT_INIT = '图片未加载'
}

/**
 *  标注-绘画基类
 */
export class DmpImgBasicPaint {
  /** canvas挂载的dom */
  dom: HTMLCanvasElement | null

  /** fabric canvas实例 */
  canvas: fabric.Canvas | null

  /** 图片实例 */
  image: fabric.Image | null

  /** 图片缩放比例（用于计算坐标偏移量） */
  imgScale: number

  /** 画布旋转角度 */
  angle: number

  /** 画布缩放比例（值越大，画布展示区域越小） */
  zoom: number
  maxZoom: number
  minZoom: number

  /** 绘画状态 */
  paintStatus: PaintStatus

  /** 鼠标点击时的初始位置 */
  mouseStartPosition: null | {
    x: number
    y: number
  }

  constructor(options?: DmpImgPaintOptions) {
    console.log('options', options)

    this.dom = null
    this.canvas = null
    this.image = null

    this.imgScale = 1

    this.angle = options?.angle || 0

    this.zoom = 1
    this.minZoom = 1
    this.maxZoom = 5

    this.paintStatus = 'dragCanvas'

    this.mouseStartPosition = null
  }
  /**
   * 初始化
   * @param dom canvas挂在的dom
   */
  init(dom: HTMLCanvasElement) {
    this.dom = dom

    // 创建画布
    this.canvas = new fabric.Canvas(dom, {
      // 启用右键，button的数字为3
      fireRightClick: true,
      // 禁止默认右键菜单
      stopContextMenu: true
    })
    this.canvas.defaultCursor = 'grab'

    this.onEvent()
  }

  /**
   * 渲染画布
   * @returns 渲染画布
   */
  renderAll() {
    if (!this.canvas) {
      message.error(ERROR_MSG.CANVAS_NOT_INIT)
      return
    }
    this.canvas.renderAll()
  }

  /** 设置画笔状态 */
  setStatus(status: PaintStatus) {
    if (!this.canvas) {
      message.error(ERROR_MSG.CANVAS_NOT_INIT)
      return
    }

    this.paintStatus = status
    switch (status) {
      case 'none':
        this.canvas.defaultCursor = 'default'
        break
      case 'dragCanvas':
        this.canvas.defaultCursor = 'grab'
        // this.canvas?.defaultCursor = 'grab'
        break
      default:
        break
    }
  }

  /* 操作画布------------------------------------------------------------------------------------------------------- */
  /**  改变画布大小 */
  resizeCanvas(options: PaintResizeOptions) {
    if (!this.canvas) {
      message.error(ERROR_MSG.CANVAS_NOT_INIT)
      return
    }

    if (options.w) {
      this.canvas.setWidth(options.w)
    }
    if (options.h) {
      this.canvas.setHeight(options.h)
    }
  }
  /** 旋转画布 */
  rotate(angle = 90) {
    if (!this.canvas) {
      message.error(ERROR_MSG.CANVAS_NOT_INIT)
      return { x: 0, y: 0 }
    }

    this.angle = (this.angle + angle) % 360

    this.resetZoom()

    this.rotateImage()

    this.canvas.renderAll()

    fabric.util.requestAnimFrame(() => {})
  }
  /** 重置画布 */
  reset() {
    if (!this.canvas) {
      message.error(ERROR_MSG.CANVAS_NOT_INIT)
      return
    }

    this.angle = 0
    this.rotateImage()
    this.resetZoom()
    this.setStatus('dragCanvas')

    this.centerCanvas()

    this.canvas.renderAll()
  }
  /** 销毁画布 */
  dispose() {
    this.canvas?.dispose()
  }
  /** 视口回到画布中心点 */
  centerCanvas() {
    if (!this.canvas || !this.canvas.viewportTransform) {
      message.error(ERROR_MSG.CANVAS_NOT_INIT)
      return
    }
    // 获取当前视图中心点的坐标
    const currentCenter = {
      x: this.canvas.width! / 2 - this.canvas.viewportTransform[4],
      y: this.canvas.height! / 2 - this.canvas.viewportTransform[5]
    }

    // 计算需要移动的距离
    const delta = {
      x: -(this.canvas.width! / 2 - currentCenter.x),
      y: -(this.canvas.height! / 2 - currentCenter.y)
    }

    console.log('delta', delta)

    // 平移画布
    this.canvas.relativePan(delta)
  }
  /* 操作画布end------------------------------------------------------------------------------------------------------- */

  /* 背景图------------------------------------------------------------------------------------------------------- */
  /** 加载图片 */
  loadImage(url: string) {
    return new Promise((rs, rj) => {
      fabric.Image.fromURL(url, image => {
        console.log('this.image:',this.image);
        if (!this.canvas) {
          rj(ERROR_MSG.CANVAS_NOT_INIT)
          return
        }
        console.log('image:',image);

        this.image = image
        

        if (!this.image.width || !this.image.height) {
          rj('图片加载失败')
          return
        }

        /* 根据旋转角度判断土图片长短边 */
        if (this.angle === 0 || this.angle === 180) {
          this.imgScale = Math.min(this.canvas.getWidth() / this.image.width, this.canvas.getHeight() / this.image.height)
        } else {
          this.imgScale = Math.min(this.canvas.getWidth() / this.image.height, this.canvas.getHeight() / this.image.width)
        }
        this.image.rotate(this.angle)
        this.image.scale(this.imgScale)

        this.image.set({
          // 禁止显示控制角
          hasControls: false,
          selectable: false,
          evented: false,
          type: 'image'
        })
        // 将图片添加到画布
        this.canvas.add(this.image)
        // 使图片居中
        this.canvas.centerObject(this.image)
        // 渲染画布
        this.canvas.renderAll()

        fabric.util.requestAnimFrame(() => {
          rs(true)
        })
      })
    })
  }

  /** 旋转图片 */
  rotateImage() {
    if (!this.canvas) {
      message.error(ERROR_MSG.CANVAS_NOT_INIT)
      return { x: 0, y: 0 }
    }
    if (!this.image || !this.image.width || !this.image.height) {
      message.error('图片加载失败')
      return
    }
    /* 根据旋转角度判断土图片长短边 */
    if (this.angle === 0 || this.angle === 180) {
      this.imgScale = Math.min(this.canvas.getWidth() / this.image.width, this.canvas.getHeight() / this.image.height)
    } else {
      this.imgScale = Math.min(this.canvas.getWidth() / this.image.height, this.canvas.getHeight() / this.image.width)
    }
    this.image.rotate(this.angle)
    this.image.scale(this.imgScale)
    this.canvas.centerObject(this.image)
    // 渲染画布
    this.canvas.renderAll()
  }

  /**
   * @returns 图片是否初始化完成
   */
  isImageInitOk(): boolean {
    return (
      this.image !== null &&
      this.image.width !== undefined &&
      this.image.height !== undefined &&
      this.image.top !== undefined &&
      this.image.left !== undefined
    )
  }
  /* 背景图end------------------------------------------------------------------------------------------------------- */

  /* 获取画布信息------------------------------------------------------------------------------------------------------- */
  /** 获取当前画布视口的中心点 */
  getCanvasViewCenter() {
    if (!this.canvas) {
      message.error(ERROR_MSG.CANVAS_NOT_INIT)
      return { x: 0, y: 0 }
    }
    const canvasWidth = this.canvas.getWidth()
    const canvasHeight = this.canvas.getHeight()
    const zoom = this.canvas.getZoom()
    const viewportTransform = this.canvas.viewportTransform!
    const centerX = (canvasWidth / 2 - viewportTransform[4]) / zoom
    const centerY = (canvasHeight / 2 - viewportTransform[5]) / zoom

    return { x: centerX, y: centerY }
  }
  /** 获取画布的中心点 */
  getCanvasCenter() {
    if (!this.canvas) {
      message.error(ERROR_MSG.CANVAS_NOT_INIT)
      return { x: 0, y: 0 }
    }
    const canvasWidth = this.canvas.getWidth()
    const canvasHeight = this.canvas.getHeight()
    const centerX = canvasWidth / 2
    const centerY = canvasHeight / 2

    return { x: centerX, y: centerY }
  }
  /* 获取画布信息end------------------------------------------------------------------------------------------------------- */

  /* 画布缩放------------------------------------------------------------------------------------------------------- */
  /** 放大画布 */
  zoomCanvasIn(point?: fabric.Point) {
    console.log('zoomCanvasIn', this)
    console.log(this.zoom, this.minZoom)
    console.log('zoomCanvasIn')

    if (this.zoom >= this.maxZoom) return
    this.zoom += 0.2

    // 没有传入点的话，就取画布中心点
    const centerPoint = this.getCanvasViewCenter()
    point ??= new fabric.Point(centerPoint.x, centerPoint?.y)

    this.canvas?.zoomToPoint(point, this.zoom)

    if (this.paintStatus === 'none') {
      this.setStatus('dragCanvas')
    }
  }
  /** 缩小画布 */
  zoomCanvasOut(point?: fabric.Point) {
    console.log('zoomCanvasOut')

    if (this.zoom <= this.minZoom) return

    this.zoom -= 0.2

    // 没有传入点的话，就取画布中心点，或者取视口中心点
    const centerPoint = this.zoom !== 1 ? this.getCanvasViewCenter() : this.getCanvasCenter()
    point ??= new fabric.Point(centerPoint.x, centerPoint?.y)
    this.canvas?.zoomToPoint(point, this.zoom)

    // 如果缩放之后比例为1，并且画布是拖拽状态，则重置状态
    if (this.zoom === 1) {
      this.centerCanvas()
      // if (this.paintStatus === 'dragCanvas') {
      //   this.setStatus('none')
      // }
    }
  }
  /** 重置画布缩放 */
  resetZoom() {
    this.zoom = 1
    const centerPoint = this.getCanvasCenter()
    const point = new fabric.Point(centerPoint.x, centerPoint?.y)
    this.canvas?.zoomToPoint(point, this.zoom)
    // if (this.paintStatus === 'dragCanvas') {
    //   this.setStatus('none')
    // }
  }
  /* 画布缩放end------------------------------------------------------------------------------------------------------- */

  /**
   * 监听画布各种事件
   */
  onEvent() {
    if (this.canvas === null) {
      message.error(ERROR_MSG.CANVAS_NOT_INIT)
      return
    }

    this.canvas.on('mouse:down', e => {
      console.log('mouse:down', e)

      switch (this.paintStatus) {
        case 'dragCanvas':
          if (this.canvas === null) {
            message.error(ERROR_MSG.CANVAS_NOT_INIT)
            return
          }

          if (e.e.button === 0) {
            // 检查是否是鼠标左键点击
            // 记录鼠标点击时的初始位置
            this.mouseStartPosition = this.canvas.getPointer(e.e)
          }
          break

        default:
          break
      }
    })
    this.canvas.on('mouse:move', e => {
      switch (this.paintStatus) {
        case 'dragCanvas':
          if (e.e.buttons === 1 && this.mouseStartPosition) {
            // 检查是否是鼠标左键按住并移动
            // 计算鼠标当前位置和初始位置之间的差值
            const mouseCurrentPosition = this.canvas.getPointer(e.e)
            const delta = {
              x: mouseCurrentPosition.x - this.mouseStartPosition.x,
              y: mouseCurrentPosition.y - this.mouseStartPosition.y
            }

            // 平移画布
            this.canvas.relativePan(delta)
          }
          break

        default:
          break
      }
    })
    this.canvas.on('mouse:up', e => {
      console.log('mouse:up', e)

      switch (this.paintStatus) {
        case 'dragCanvas':
          if (e.e.button === 0) {
            // 检查是否是鼠标左键松开
            // 重置初始位置
            this.mouseStartPosition = null
          }
          break

        default:
          break
      }
    })
    // 监听鼠标移入事件
    this.canvas.on('mouse:over', () => {})
    // 监听鼠标移出事件
    this.canvas.on('mouse:out', () => {})
    // 监听鼠标滚动事件
    this.canvas.on('mouse:wheel', options => {
      if (!this.canvas) {
        message.error(ERROR_MSG.CANVAS_NOT_INIT)
        return
      }

      switch (this.paintStatus) {
        /* 根据鼠标点放大或缩小 */
        case 'dragCanvas':
          options.e.preventDefault()
          options.e.stopPropagation()

          const delta = options.e.deltaY

          // 获取鼠标相对于 canvas 的位置
          const pointer = this.canvas.getPointer(options.e)
          const point = new fabric.Point(pointer.x, pointer.y)

          if (delta > 0) {
            this.zoomCanvasOut(point)
          } else {
            this.zoomCanvasIn(point)
          }

          break

        default:
          break
      }
    })
    this.canvas.on('object:removed', () => {})
    this.canvas.on('object:modified', e => {
      console.log(e)
    })
    // 元素改变大小
    this.canvas.on('object:scaling', () => {})
    this.canvas.on('object:moving', () => {})
    //选中图形
    this.canvas.on('selection:created', e => {
      console.log(e)
    })
    //选中图形切换
    this.canvas.on('selection:updated', e => {
      console.log(e)
    })

    this.canvas.on('selection:cleared', () => {})
  }
}
